# 依据 menu_menucfg 生成 menu_node.c

import os
import copy
import logging
from pathlib import Path,PurePath
import time

logger = logging.getLogger(__name__)
logger.setLevel(level=logging.INFO)

formatter = logging.Formatter('%(asctime)s - %(name)s [%(lineno)s] - %(levelname)s - %(message)s')
 
 
console_handler = logging.StreamHandler()  # 流句柄
console_handler.setLevel(logging.INFO)
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)
'''
    MENU_DATA_TYPE_CHAR,        //< 字符
    MENU_DATA_TYPE_RO_CHAR,     //< 字符型 只读enu
    MENU_DATA_TYPE_UINT8,       //< 8bit无符号整数
    MENU_DATA_TYPE_RO_UINT8,    //< 8bit无符号整数 只读   ro_uint8
    MENU_DATA_TYPE_INT8,        //< 8bit有符号整数
    MENU_DATA_TYPE_RO_INT8,     //< 8bit有符号整数 只读
    MENU_DATA_TYPE_UINT16,      //< 16bit无符号整数
    MENU_DATA_TYPE_RO_UINT16,   //< 16bit无符号整数 只读
    MENU_DATA_TYPE_INT16,       //< 16bit有符号整数
    MENU_DATA_TYPE_RO_INT16,    //< 16bit有符号整数 只读
    MENU_DATA_TYPE_UINT32,      //< 32bit无符号整数
    MENU_DATA_TYPE_RO_UINT32,   //< 32bit无符号整数 只读
    MENU_DATA_TYPE_INT32,       //< 32bit有符号整数
    MENU_DATA_TYPE_RO_INT32,    //< 32bit有符号整数 只读
    MENU_DATA_TYPE_IPV4,        //< ipv4 以32bit无符号整数形式存储
    MENU_DATA_TYPE_RO_IPV4      //< ipv4 以32bit无符号整数形式存储 只读
'''

READ_FNAME = "menu.menucfg"
WRITE_FNAME = "menu_node_2.c"
LOGO_FNAME = "menu.logo"

NEWLINE = "\n"

data_type = {
	"char" : "MENU_DATA_TYPE_CHAR",
	"ro_char" : "MENU_DATA_TYPE_RO_CHAR",

	"uint8" : "MENU_DATA_TYPE_UINT8",
	"ro_uint8" : "MENU_DATA_TYPE_RO_UINT8",

	"int8" : "MENU_DATA_TYPE_INT8",
	"ro_int8" : "MENU_DATA_TYPE_RO_INT8",

	"uint16" : "MENU_DATA_TYPE_UINT16",
	"ro_uint16" : "MENU_DATA_TYPE_RO_UINT16",

	"int16" : "MENU_DATA_TYPE_INT16",
	"ro_int16" : "MENU_DATA_TYPE_RO_INT16",

	"uint32" : "MENU_DATA_TYPE_UINT32",
	"ro_uint32 " : "MENU_DATA_TYPE_RO_UINT32",

	"int32" : "MENU_DATA_TYPE_INT32",
	"ro_int32" : "MENU_DATA_TYPE_RO_INT32",

	"int32" : "MENU_DATA_TYPE_IPV4",
	"ro_int32" : "MENU_DATA_TYPE_RO_IPV4",
}


menu_struct = { 
    "name" : "",
	"data_type": "",     
	"max_value": "",     
	"min_value": "",     
	"father": "",     
	"next": "",     
	"child": "",     
	"info_str": "",     
	"data": "",     
	"num": "",
	}



class menu_build(object):
	'''
	菜单 数据结构 描述
	{
		
	}
	'''

	def __init__(self,):
		self.offset_seq 	= 1
		self.readout 	= ""
		self.writein 	= ""
		self.logo 	= ""
		self.menu 		= []   # 解析到菜单字典  行号  菜单lvl  菜单行 菜单字典
		self.total_line_num = 0
		self.menu_data_type = ""
		self.max_value = ""
		self.min_value = ""
		self.father = ""
		self.next = ""
		self.child = ""
		self.info_str = ""
		self.data = ""
		self.num = ""

		self.menu_group = []  #  Format [ lvl,  [] , child_num, seq]

		self.lvl_0_cnt = 0
		self.lvl_1_cnt = 0
		self.lvl_2_cnt = 0
		self.lvl_3_cnt = 0

		self.lvl_0 = []  # all seq
		self.lvl_1  = []
		self.lvl_2 = []
		self.lvl_3 = []
		pass

	def menu_read_cfg(self,fname):
		ln = []
		line_num = 0
		menu_lvl = 0

		with open(fname,"r", encoding='utf-8') as f:
			# self.readout = f.read()
			line = f.readline()
			while line:
				ln = []
				ln.append(line_num)
				if ( line.startswith('\t') == False ):
					menu_lvl = 0
					pass
				if ( line.startswith('\t') == True ):
					menu_lvl = 1
					pass
				if ( line.startswith('\t\t') == True ):
					menu_lvl = 2
					pass
				if ( line.startswith('\t\t\t') == True ):
					menu_lvl = 3
					pass
				if ( line.startswith('\t\t\t\t') == True ):
					menu_lvl = 4
					pass
				line = line[menu_lvl:].strip('\r').strip('\n')
				ln.append(menu_lvl)
				tmp_line = line.split(' ')
				# print(tmp_line[1])
				dct = self.menu_lst_2_dct(tmp_line)
				# print(dct)
				ln.append(dct)
				self.menu.append(ln)
				line_num += 1
				line = f.readline()
			self.total_line_num = line_num  
			logger.warning(" total line : %d ", self.total_line_num)

	def menu_read_logo_2(self,fname):
		with open(fname,"r", encoding='utf-8') as f:
			self.logo = f.read()
   
	def menu_read_logo(self,fname):
		with open(fname,"r", encoding='utf-8') as f:
			line = f.readline()
			while line:
				# print(line, end = '')
				line = f.readline().strip('\n').strip('\r')
				self.logo +="\\r\\n" + line
   
	def menu_lst_2_dct(self, lst):
		dct = copy.deepcopy(menu_struct)  
		dct.update( {"name":lst[0]} )
		# 数据类型
		dct.update({"data_type" :self.menu_get_data_type(lst[1])})
		dct.update({"max_value" : self.menu_get_max_val(lst[2].strip(' ')) })
		dct.update({"min_value" : self.menu_get_min_val(lst[2].strip(' '))})
		dct.update({"father" : 0})
		dct.update({"next" : 0})
		dct.update({"child" : 0})
		dct.update({"info_str" : lst[0]})
		dct.update({"num" : lst[3].strip(" ")[1:]})
		dct.update({"data" : lst[4].strip(" ")})
		return dct

	def menu_get_data_type(self, k):
		if (k in data_type.keys()):
			return data_type.get(str(k))
		pass

	def menu_get_max_val(self, str):
		tmp = str.strip(' ')
		tmp = tmp[1:]
		tmp = tmp[:-1].split(',')[1]
		# print(tmp)
		return tmp
		pass

	def menu_get_min_val(self, str):
		tmp = str.strip(' ')
		tmp = tmp[1:]
		tmp = tmp[:-1].split(',')[0]
		# print(tmp)
		return tmp
		pass

	def menu_node_header(self,):
		'''
		默认一个主菜单   LOGO显示等
		'''
		self.writein += 	"#include \"main.h\"" + NEWLINE
		self.writein += 	"#include \"menu.h\"" + NEWLINE
		self.writein += 	"const struct menu_tree_node menu_tree[]={" + NEWLINE
		# format ['保存', 'uint8', '[0,1]', 'X0', '&operating_state.flag_write_back']
		lst = [self.logo,"char","[0,0]","X0","NULL"]
		dct_main_screen = self.menu_lst_2_dct( lst)
		self.menu_dct_update(dct_main_screen,0,0,1)
		self.menu_node_add(0,dct_main_screen)
		pass

	def menu_node_footer(self,):
		self.writein += 	"};" 
		pass


	def menu_node_body(self,):
		for i in range( len(self.menu)):
			dct:dict = self.menu[i][2]
			self.menu_node_add(i, dct)
			pass
		pass

	def menu_node_add(self,seq, dct:dict):
		self.writein += 	"\t{" + NEWLINE
		self.writein += 	"\t\t.data_type="+str(dct["data_type"])+"," + NEWLINE
		self.writein +=  "\t\t.max_value="+str(dct["max_value"])+"," + NEWLINE
		self.writein +=  "\t\t.min_value="+str(dct["min_value"])+"," + NEWLINE
		self.writein +=  "\t\t.father="+str(dct["father"])+"," + NEWLINE
		self.writein +=  "\t\t.next="+str(dct["next"])+"," + NEWLINE
		self.writein +=  "\t\t.child="+str(dct["child"])+"," + NEWLINE
		self.writein +=  "\t\t.info_str=\""+str(dct["info_str"])+"\","  + NEWLINE
		self.writein +=  "\t\t.data="+str(dct["data"])+"," + NEWLINE
		self.writein +=  "\t\t.num="+str(dct["num"])+"" + NEWLINE
		if (seq == self.total_line_num-1) :
			self.writein += 	"\t}" + NEWLINE
		else :
			self.writein += 	"\t}," + NEWLINE
 

	def menu_dct_update(self,dct:dict,father,next,child):
		dct.update( {"father": father} )
		dct.update( {"next": next} )
		dct.update( {"child": child} )
		pass

	
	def menu_process(self, ):
		'''
		lvl_0  有一个子菜单
		'''
		self.menu_group = []  #  Format : seq  lvl  father ,next , child(第一个子节点)
 
		for i in range( len(self.menu)):
			if (self.menu[i][1] == 0):
				self.lvl_0_cnt += 1
				tmp_lst = [ self.menu[i][0], self.menu[i][1], 0,i+self.offset_seq+1,i+self.offset_seq+1]
				self.menu_group.append(tmp_lst)
			if (self.menu[i][1] == 1):
				self.lvl_1_cnt+=1
				tmp_lst = [ self.menu[i][0], self.menu[i][1], 0,i+self.offset_seq+1,i+self.offset_seq+1]
				self.menu_group.append(tmp_lst)
			if (self.menu[i][1] == 2):
				tmp_lst = [ self.menu[i][0], self.menu[i][1], 0,i+self.offset_seq+1,i+self.offset_seq+1]
				self.menu_group.append(tmp_lst)
				self.lvl_2_cnt += 1
			if (self.menu[i][1] == 3):
				self.lvl_3_cnt += 1  
				tmp_lst = [ self.menu[i][0], self.menu[i][1], 0,i+self.offset_seq+1,i+self.offset_seq+1]
				self.menu_group.append(tmp_lst)

		# logger.info (" number  %d  %d  %d  %d",self.lvl_0_cnt,self.lvl_1_cnt,self.lvl_2_cnt,self.lvl_3_cnt)
		# self.menu_process_lvl_1( )
		self.menu_process_lvl_0( )
		self.menu_process_lvl_1( )
		self.menu_process_lvl_2( )
		self.menu_process_lvl_3( )

		# self.menu_print_dict_3para()
		# self.menu_print_dict_3para(0)
		# self.menu_print_dict_3para(1)
		# self.menu_print_dict_3para(2)
		# self.menu_print_dict_3para(3)

	# process  father  next  child
	#lvl 0  修改next
	def menu_process_lvl_0(self, ):
        #lvl 0  修改next
		father = 2
		next = 3
		child = 4
		target_lvl 	= 0  	# 目标lvl
		current_lvl = 0		# 当前lvl
		current_seq = 0		# 当前序号
		lvl_father = 0
 
		for i in range( len(self.menu)):
			current_seq = self.menu[i][0]
			current_lvl = self.menu_group[i][1]

			if ( current_lvl == target_lvl ):
				# set current father  next child
				_father = lvl_father
    
				_next =  self.menu_node_has_next(current_seq,current_lvl)
				self.menu_group[current_seq][next] = _next 
    
				_child =   self.menu_node_has_child(current_seq,current_lvl)
				if (_child == 0):
					_child = _child
				else:
					_child = _child+self.offset_seq
				self.menu_group[current_seq][child] = _child
				self.menu_node_update_3para_by_seq(current_seq,_father,_next,_child )

	# #lvl 1  修改本身next, 上级的child, father
	def menu_process_lvl_1(self, ):		
		father = 2
		next = 3
		child = 4
		target_lvl 	= 1  	# 目标lvl
		current_lvl = 0		# 当前lvl
		current_seq = 0		# 当前序号
		lvl_father = 0
		is_first_item = 1
		flag = 0
		for i in range( len(self.menu)):
			current_seq = self.menu_group[i][0]
			current_lvl = self.menu_group[i][1]

			# father found
			if(current_lvl == target_lvl-1):
				lvl_father = current_seq
				flag = 1

			# first item found
			if(current_lvl == target_lvl and flag >= 1 ):
				flag = 2

			# first item deal
			if((current_lvl == target_lvl) and (flag == 2 )and (is_first_item == 1)):
				if ( i==0 ):
					assert("error in menu_process_lvl_1,  menu.menucfg")
				# set current father  next child
				_father = lvl_father+self.offset_seq
    
				_next =  self.menu_node_has_next(current_seq,current_lvl)
				self.menu_group[current_seq][next] = _next 

				_child =   self.menu_node_has_child(current_seq,current_lvl)
				if (_child == 0):
					_child = _child
				else:
					_child = _child+self.offset_seq
				self.menu_group[current_seq][child] = _child
				self.menu_node_update_3para_by_seq(current_seq,_father,_next,_child )
    
			# next item
			if( (current_lvl == target_lvl) and (flag == 2) and (is_first_item == 0) ):
				# set current father  next child
				_father = lvl_father+self.offset_seq
    
				_next =  self.menu_node_has_next(current_seq,current_lvl)
				self.menu_group[current_seq][next] = _next 

				_child =   self.menu_node_has_child(current_seq,current_lvl)
				if (_child == 0):
					_child = _child
				else:
					_child = _child+self.offset_seq
				self.menu_group[current_seq][child] = _child
				self.menu_node_update_3para_by_seq(current_seq,_father,_next,_child )

	# #lvl 2
	def menu_process_lvl_2(self, ):		
		father = 2
		next = 3
		child = 4
		target_lvl 	= 2  	# 目标lvl
		current_lvl = 0		# 当前lvl
		current_seq = 0		# 当前序号
		lvl_father = 0
		is_first_item = 1
		flag = 0
		for i in range( len(self.menu)):
			current_seq = self.menu_group[i][0]
			current_lvl = self.menu_group[i][1]

			# father found
			if(current_lvl == target_lvl-1):
				lvl_father = current_seq
				flag = 1

			# first item found
			if(current_lvl == target_lvl and flag >= 1 ):
				flag = 2

			# first item deal
			if((current_lvl == target_lvl) and (flag == 2 )and (is_first_item == 1)):
				if ( i==0 ):
					assert("error in menu_process_lvl_1,  menu.menucfg")
				# set current father  next child
				_father = lvl_father+self.offset_seq
    
				_next =  self.menu_node_has_next(current_seq,current_lvl)
				self.menu_group[current_seq][next] = _next 

				_child =   self.menu_node_has_child(current_seq,current_lvl)
				if (_child == 0):
					_child = _child
				else:
					_child = _child+self.offset_seq
				self.menu_group[current_seq][child] = _child
				self.menu_node_update_3para_by_seq(current_seq,_father,_next,_child )
				# print(f"menu_process_lvl  {current_seq}  {current_lvl}  ==   {_father} {_next}   {_child}")
			# next item
			if( (current_lvl == target_lvl) and (flag == 2) and (is_first_item == 0) ):
				# set current father  next child
				_father = lvl_father+self.offset_seq
    
				_next =  self.menu_node_has_next(current_seq,current_lvl)
				self.menu_group[current_seq][next] = _next 

				_child =   self.menu_node_has_child(current_seq,current_lvl)
				if (_child == 0):
					_child = _child
				else:
					_child = _child+self.offset_seq
				self.menu_group[current_seq][child] = _child
				self.menu_node_update_3para_by_seq(current_seq,_father,_next,_child )
	#lvl 3
	def menu_process_lvl_3(self, ):		
		father = 2
		next = 3
		child = 4
		target_lvl 	= 3  	# 目标lvl
		current_lvl = 0		# 当前lvl
		current_seq = 0		# 当前序号
		lvl_father = 0
		is_first_item = 1
		flag = 0
		for i in range( len(self.menu)):
			current_seq = self.menu_group[i][0]
			current_lvl = self.menu_group[i][1]

			# father found
			if(current_lvl == target_lvl-1):
				lvl_father = current_seq
				flag = 1

			# first item found
			if(current_lvl == target_lvl and flag >= 1 ):
				flag = 2

			# first item deal
			if((current_lvl == target_lvl) and (flag == 2 )and (is_first_item == 1)):
				if ( i==0 ):
					assert("error in menu_process_lvl_1,  menu.menucfg")
				# set current father  next child
				_father = lvl_father+self.offset_seq
    
				_next =  self.menu_node_has_next(current_seq,current_lvl)
				self.menu_group[current_seq][next] = _next 

				_child =   self.menu_node_has_child(current_seq,current_lvl)
				if (_child == 0):
					_child = _child
				else:
					_child = _child+self.offset_seq
				self.menu_group[current_seq][child] = _child
				self.menu_node_update_3para_by_seq(current_seq,_father,_next,_child )
				# print(f"menu_process_lvl  {current_seq}  {current_lvl}  ==   {_father} {_next}   {_child}")
			# next item
			if( (current_lvl == target_lvl) and (flag == 2) and (is_first_item == 0) ):
				# set current father  next child
				_father = lvl_father+self.offset_seq
    
				_next =  self.menu_node_has_next(current_seq,current_lvl)
				self.menu_group[current_seq][next] = _next 

				_child =   self.menu_node_has_child(current_seq,current_lvl)
				if (_child == 0):
					_child = _child
				else:
					_child = _child+self.offset_seq
				self.menu_group[current_seq][child] = _child
				self.menu_node_update_3para_by_seq(current_seq,_father,_next,_child )



	def menu_node_has_child(self,seq,lvl):
		if (seq >= self.total_line_num -1):
			return 0
		if (self.menu_group[seq+1][1] == lvl+1):
			return seq+1
		return 0
		pass

	def menu_node_has_next(self,seq,lvl):
		if (seq > self.total_line_num -1):
			return 0
		for s in range(seq+1,self.total_line_num):
			# next lvl become little, no next,  return 0
			if (self.menu_group[s][1] < lvl):
				return 0
 
			if (self.menu_group[s][1] == lvl):
				return s+1
		return 0

	def menu_node_update_3para_by_seq(self,seq,father,next,child):
		print( f" menu_node_update_3para_by_seq  {seq} {father}  {next}  {child}" )
		print( f" menu_node_update_3para_by_seq  { self.menu[seq]}  " )
			 
		dct:dict = self.menu[seq][2]
		self.menu[seq][2].update({'father': father})
		self.menu[seq][2].update({'next': next})
		self.menu[seq][2].update({'child': child})
		return 0



	def menu_write_cfg(self,fname):
		with open(fname, "w", encoding='utf-8') as f:
			f.write(self.writein)

	def menu_print_dict(self, lvl=None):
		print(f"============= menu_print_dict   LVL_{lvl} ==============")
		for i in range( len(self.menu)):
			if (lvl == None) :
				print(f" ==== seq {self.menu[i][0]}, lvl {self.menu[i][1]} ,  {self.menu[i][3]}")
			else:				
				if (self.menu[i][1] == lvl):
					print(f"seq {self.menu[i][0]}, lvl {self.menu[i][1]} ,  {self.menu[i][3]}")
			pass
		print(f"============= menu_print_dict  ==============")

	def menu_print_dict_4para(self, lvl=None):
		print(f"============= menu_print_dict_4para   LVL_{lvl} ==============")
		for i in range( len(self.menu)):
			_name = self.menu[i][3].get('name')
			_father = self.menu[i][3].get('father')
			_child = self.menu[i][3].get('child')
			_next = self.menu[i][3].get('next')
			if (lvl == None) :
				print(f" ==== seq {self.menu[i][0]}, lvl {self.menu[i][1]} ,  \t{_father}\t{_next}\t{_child}\t{_name}")
			else:				
				if (self.menu[i][1] == lvl):
					print(f"seq {self.menu[i][0]}, lvl {self.menu[i][1]} ,   \t{_father}\t{_next}\t{_child}\t{_name}")			
		pass
		print(f"============= menu_print_dict_4para  ==============")

	def menu_print_dict_3para(self, lvl=None):
		print(f"============= menu_print_dict_3para   LVL_{lvl} ==============")
		for i in range( len(self.menu)):
			_name = self.menu[i][3].get('name')
			_father = self.menu[i][3].get('father')
			_child = self.menu[i][3].get('child')
			_next = self.menu[i][3].get('next')
			if (lvl == None) :
				print(f" ==== seq {self.menu[i][0]}, lvl {self.menu[i][1]} ,  \t{_father}\t{_next}\t{_child} ")
			else:				
				if (self.menu[i][1] == lvl):
					print(f"seq {self.menu[i][0]}, lvl {self.menu[i][1]} ,   \t{_father}\t{_next}\t{_child}")
						
		pass
		print(f"============= menu_print_dict_3para  ==============")
  
	def menu_print_c_file(self,):
		print( self.writein )

	def menu_print_menugroup(self, lvl=None):
		print(f"============= menu_print_menugroup  LVL_{lvl} ==============")
		for i in range( len(self.menu_group)):
			if (lvl == None) :
				print(self.menu_group[i])
			else:				
				if (self.menu_group[i][1] == lvl):
					print(self.menu_group[i])
			pass
		print(f"============= menu_print_menugroup ==============")


	pass


if __name__ == '__main__':
	# logging.basicConfig(level = logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
	logger.info('Build menu_node ......')
	mb = menu_build()
	pth = Path.cwd()
	dir = "Menu"
 

	logger.info("Read File============ %s" , pth)

	f_read_pth = pth.joinpath(dir, READ_FNAME)
	mb.menu_read_cfg(f_read_pth)
 
	f_logo_pth = pth.joinpath(dir, LOGO_FNAME)
	mb.menu_read_logo(f_logo_pth)
	# logger.info(mb.logo)
	f_write_pth = pth.joinpath(dir, WRITE_FNAME)

	logger.info("Build============ %s" , pth)
	mb.menu_process()
	mb.menu_node_header()
	mb.menu_node_body()
	mb.menu_node_footer()


	logger.info("RUN test============ %s" , pth)
	# mb.menu_print_c_file( )
	# mb.menu_print_dict_4para()
	# mb.menu_print_dict()

	f_write_pth = pth.joinpath(dir, WRITE_FNAME)
	mb.menu_write_cfg(f_write_pth)
	# logo = ""
	# with open(f_logo_pth,"r", encoding='utf-8') as f:
	# 	line = f.readline()
	# 	while line:
	# 		# print(line, end = '')
	# 		line = f.readline().strip('\n').strip('\r')
	# 		logo +="\\r\\n" + line
   
	# print(logo)
  
	# t_str = "\r\noooooooo"
	# print(t_str)
	# tt_str = "\\r\\noooooooo"
	# print(tt_str)
 
 
	# logger.info('Test  ......')

	# print(mb.menu_node_has_next(32,1))
	# print(mb.menu_node_has_next(32,1))

	# f_write_pth = pth.joinpath(dir, WRITE_FNAME)
	# mb.menu_read_cfg(f_write_pth)
 
	# mb.menu_print_c_file( )
 
	# mb.menu_print_dict()
























# test res:

# seq 0, lvl 0 ,          0       0       2


# seq 1, lvl 1 ,          1       4       3
# seq 3, lvl 1 ,          1       25      5
# seq 24, lvl 1 ,         1       28      26
# seq 27, lvl 1 ,         1       30      29
# seq 29, lvl 1 ,         1       31      0
# seq 30, lvl 1 ,         1       32      0
# seq 31, lvl 1 ,         1       33      0
# seq 32, lvl 1 ,         1       0       0


# seq 2, lvl 2 ,          2       0       0
# seq 4, lvl 2 ,          4       9       6
# seq 8, lvl 2 ,          4       13      10
# seq 12, lvl 2 ,         4       17      14
# seq 16, lvl 2 ,         4       21      18
# seq 20, lvl 2 ,         4       0       22
# seq 25, lvl 2 ,         25      27      0
# seq 26, lvl 2 ,         25      0       0
# seq 28, lvl 2 ,         28      0       0


# ============= menu_print_dict_3para   LVL_3 ==============
# seq 5, lvl 3 ,          5       7       0
# seq 6, lvl 3 ,          5       8       0
# seq 7, lvl 3 ,          5       0       0
# seq 9, lvl 3 ,          9       11      0
# seq 10, lvl 3 ,         9       12      0
# seq 11, lvl 3 ,         9       0       0
# seq 13, lvl 3 ,         13      15      0
# seq 14, lvl 3 ,         13      16      0
# seq 15, lvl 3 ,         13      0       0
# seq 17, lvl 3 ,         17      19      0
# seq 18, lvl 3 ,         17      20      0
# seq 19, lvl 3 ,         17      0       0
# seq 21, lvl 3 ,         21      23      0
# seq 22, lvl 3 ,         21      24      0
# seq 23, lvl 3 ,         21      0       0



# ============= menu_print_dict_4para   LVL_None ==============
#  ==== seq 0, lvl 0 ,    0       0       2       菜单
#  ==== seq 1, lvl 1 ,    1       4       3       设备配置
#  ==== seq 2, lvl 2 ,    2       0       0       设备ID
#  ==== seq 3, lvl 1 ,    1       25      5       串口配置
#  ==== seq 4, lvl 2 ,    4       9       6       串口1配置\r\n传感器1
#  ==== seq 5, lvl 3 ,    5       7       0       波特率
#  ==== seq 6, lvl 3 ,    5       8       0       奇偶校验\r\n不校验:0\r\n奇校验:1024\r\n偶校验:1536
#  ==== seq 7, lvl 3 ,    5       0       0       停止位\r\n1bit:0\r\n0.5bit:4096\r\n2bit:8192\r\n1.5bit:12288
#  ==== seq 8, lvl 2 ,    4       13      10      串口2配置\r\n传感器2
#  ==== seq 9, lvl 3 ,    9       11      0       波特率
#  ==== seq 10, lvl 3 ,   9       12      0       奇偶校验\r\n不校验:0\r\n奇校验:1024\r\n偶校验:1536
#  ==== seq 11, lvl 3 ,   9       0       0       停止位\r\n1bit:0\r\n0.5bit:4096\r\n2bit:8192\r\n1.5bit:12288
#  ==== seq 12, lvl 2 ,   4       17      14      串口3配置\r\n传感器3
#  ==== seq 13, lvl 3 ,   13      15      0       波特率
#  ==== seq 14, lvl 3 ,   13      16      0       奇偶校验\r\n不校验:0\r\n奇校验:1024\r\n偶校验:1536
#  ==== seq 15, lvl 3 ,   13      0       0       停止位\r\n1bit:0\r\n0.5bit:4096\r\n2bit:8192\r\n1.5bit:12288
#  ==== seq 16, lvl 2 ,   4       21      18      串口4配置\r\nWK2114
#  ==== seq 17, lvl 3 ,   17      19      0       波特率
#  ==== seq 18, lvl 3 ,   17      20      0       奇偶校验\r\n不校验:0\r\n奇校验:1024\r\n偶校验:1536
#  ==== seq 19, lvl 3 ,   17      0       0       停止位\r\n1bit:0\r\n0.5bit:4096\r\n2bit:8192\r\n1.5bit:12288
#  ==== seq 20, lvl 2 ,   4       0       22      串口6配置\r\nLOG
#  ==== seq 21, lvl 3 ,   21      23      0       波特率
#  ==== seq 22, lvl 3 ,   21      24      0       奇偶校验\r\n不校验:0\r\n奇校验:1024\r\n偶校验:1536
#  ==== seq 23, lvl 3 ,   21      0       0       停止位\r\n1bit:0\r\n0.5bit:4096\r\n2bit:8192\r\n1.5bit:12288
#  ==== seq 24, lvl 1 ,   1       28      26      网络配置
#  ==== seq 25, lvl 2 ,   25      27      0       服务器域名
#  ==== seq 26, lvl 2 ,   25      0       0       服务器端口
#  ==== seq 27, lvl 1 ,   1       30      29      传感器配置
#  ==== seq 28, lvl 2 ,   28      0       0       传感器标定文件路径
#  ==== seq 29, lvl 1 ,   1       31      0       保存
#  ==== seq 30, lvl 1 ,   1       32      0       重启
#  ==== seq 31, lvl 1 ,   1       33      0       恢复出厂设置\r\n警告:此选项会清空所有用户配置且不可逆,是否继续?
#  ==== seq 32, lvl 1 ,   1       0       0       版本
# ============= menu_print_dict_4para  ==============













##  菜单名称  类型   范围    数量   数据来源

""" 
菜单 uint8 [0,0] X0 NULL
	设备配置 uint8 [0,0] X0 NULL
		设备ID uint16 [0,255] X0 &config.device_id	
	串口配置 uint8 [0,0] X0 NULL
		串口1配置\r\n传感器1 uint8 [0,0] X0 NULL
			波特率 uint32 [4800,4000000] X0 &config.uart1.buad
			奇偶校验\r\n不校验:0\r\n奇校验:1024\r\n偶校验:1536 uint16 [0,1536] X0 &config.uart1.parity
			停止位\r\n1bit:0\r\n0.5bit:4096\r\n2bit:8192\r\n1.5bit:12288 uint16 [0,12288] X0 &config.uart1.stopbits
		串口2配置\r\n传感器2 uint8 [0,0] X0 NULL
			波特率 uint32 [4800,4000000] X0 &config.uart1.buad
			奇偶校验\r\n不校验:0\r\n奇校验:1024\r\n偶校验:1536 uint16 [0,1536] X0 &config.uart1.parity
			停止位\r\n1bit:0\r\n0.5bit:4096\r\n2bit:8192\r\n1.5bit:12288 uint16 [0,12288] X0 &config.uart2.stopbits
		串口3配置\r\n传感器3 uint8 [0,0] X0 NULL
			波特率 uint32 [4800,4000000] X0 &config.uart1.buad
			奇偶校验\r\n不校验:0\r\n奇校验:1024\r\n偶校验:1536 uint16 [0,1536] X0 &config.uart1.parity
			停止位\r\n1bit:0\r\n0.5bit:4096\r\n2bit:8192\r\n1.5bit:12288 uint16 [0,12288] X0 &config.uart3.stopbits
		串口4配置\r\nWK2114 uint8 [0,0] X0 NULL
			波特率 uint32 [4800,4000000] X0 &config.uart3.buad
			奇偶校验\r\n不校验:0\r\n奇校验:1024\r\n偶校验:1536 uint16 [0,1536] X0 &config.uart3.parity
			停止位\r\n1bit:0\r\n0.5bit:4096\r\n2bit:8192\r\n1.5bit:12288 uint16 [0,12288] X0 &config.uart4.stopbits
		串口6配置\r\nLOG uint8 [0,0] X0 NULL
			波特率 uint32 [4800,4000000] X0 &config.uart6.buad
			奇偶校验\r\n不校验:0\r\n奇校验:1024\r\n偶校验:1536 uint16 [0,1536] X0 &config.uart6.parity
			停止位\r\n1bit:0\r\n0.5bit:4096\r\n2bit:8192\r\n1.5bit:12288 uint16 [0,12288] X0 &config.uart6.stopbits
	网络配置 uint8 [0,0] X0 NULL
		服务器域名 char [0,255] X64 config.tcp.server_ipv4
		服务器端口 uint16 [0,65535] X0 &config.tcp.server_port
	传感器配置 uint8 [0,0] X0 NULL
		传感器标定文件路径 char [0,255] X64 &config.ini_filename[3]
	保存 uint8 [0,1] X0 &operating_state.flag_write_back
	重启 uint8 [0,1] X0 &operating_state.flag_reboot
	恢复出厂设置\r\n警告:此选项会清空所有用户配置且不可逆,是否继续? uint8 [0,1] X0 &operating_state.flag_reset
	版本 ro_uint8 [0,0] X3 config.version 
"""

"""
#include "menu.h"
#include "main.h"
const struct menu_tree_node menu_tree[]={
    {
        .data_type=MENU_DATA_TYPE_CHAR,
        .max_value=0,
        .min_value=0,
        .father=0,
        .next=0,
        .child=1,
        .info_str="\r\n                        ███████╗███████╗███████╗ █████╗ \r\n                        ██╔════╝██╔════╝██╔════╝██╔══██╗\r\n                        █████╗  ███████╗█████╗  ███████║\r\n                        ██╔══╝  ╚════██║██╔══╝  ██╔══██║\r\n                        ███████╗███████║███████╗██║  ██║\r\n                        ╚══════╝╚══════╝╚══════╝╚═╝  ╚═╝\r\n\r\n                             逸海光学(青岛)科技有限公司\r\n\r\n                                手持式光辐射测量装置\r\n",
        .data=NULL,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT8,
        .max_value=0,
        .min_value=0,
        .father=0,
        .next=0,
        .child=2,
        .info_str="菜单",
        .data=NULL,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT8,
        .max_value=0,
        .min_value=0,
        .father=1,
        .next=4,
        .child=3,
        .info_str="设备配置",
        .data=NULL,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT16,
        .max_value=255,
        .min_value=0,
        .father=2,
        .next=0,
        .child=0,
        .info_str="设备ID",
        .data=&config.device_id,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT8,
        .max_value=0,
        .min_value=0,
        .father=1,
        .next=25,
        .child=5,
        .info_str="串口配置",
        .data=NULL,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT8,
        .max_value=0,
        .min_value=0,
        .father=4,
        .next=9,
        .child=6,
        .info_str="串口1配置\r\n传感器1",
        .data=NULL,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT32,
        .max_value=4000000,
        .min_value=4800,
        .father=5,
        .next=7,
        .child=0,
        .info_str="波特率",
        .data=&config.uart1.buad,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT16,
        .max_value=1536,
        .min_value=0,
        .father=5,
        .next=8,
        .child=0,
        .info_str="奇偶校验\r\n不校验:0\r\n奇校验:1024\r\n偶校验:1536",
        .data=&config.uart1.parity,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT16,
        .max_value=12288,
        .min_value=0,
        .father=5,
        .next=0,
        .child=0,
        .info_str="停止位\r\n1bit:0\r\n0.5bit:4096\r\n2bit:8192\r\n1.5bit:12288",
        .data=&config.uart1.stopbits,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT8,
        .max_value=0,
        .min_value=0,
        .father=4,
        .next=13,
        .child=10,
        .info_str="串口2配置\r\n传感器2",
        .data=NULL,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT32,
        .max_value=4000000,
        .min_value=4800,
        .father=9,
        .next=11,
        .child=0,
        .info_str="波特率",
        .data=&config.uart1.buad,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT16,
        .max_value=1536,
        .min_value=0,
        .father=9,
        .next=12,
        .child=0,
        .info_str="奇偶校验\r\n不校验:0\r\n奇校验:1024\r\n偶校验:1536",
        .data=&config.uart1.parity,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT16,
        .max_value=12288,
        .min_value=0,
        .father=9,
        .next=0,
        .child=0,
        .info_str="停止位\r\n1bit:0\r\n0.5bit:4096\r\n2bit:8192\r\n1.5bit:12288",
        .data=&config.uart2.stopbits,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT8,
        .max_value=0,
        .min_value=0,
        .father=4,
        .next=17,
        .child=14,
        .info_str="串口3配置\r\n传感器3",
        .data=NULL,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT32,
        .max_value=4000000,
        .min_value=4800,
        .father=13,
        .next=15,
        .child=0,
        .info_str="波特率",
        .data=&config.uart1.buad,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT16,
        .max_value=1536,
        .min_value=0,
        .father=13,
        .next=16,
        .child=0,
        .info_str="奇偶校验\r\n不校验:0\r\n奇校验:1024\r\n偶校验:1536",
        .data=&config.uart1.parity,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT16,
        .max_value=12288,
        .min_value=0,
        .father=13,
        .next=0,
        .child=0,
        .info_str="停止位\r\n1bit:0\r\n0.5bit:4096\r\n2bit:8192\r\n1.5bit:12288",
        .data=&config.uart3.stopbits,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT8,
        .max_value=0,
        .min_value=0,
        .father=4,
        .next=21,
        .child=18,
        .info_str="串口4配置\r\nWK2114",
        .data=NULL,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT32,
        .max_value=4000000,
        .min_value=4800,
        .father=17,
        .next=19,
        .child=0,
        .info_str="波特率",
        .data=&config.uart3.buad,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT16,
        .max_value=1536,
        .min_value=0,
        .father=17,
        .next=20,
        .child=0,
        .info_str="奇偶校验\r\n不校验:0\r\n奇校验:1024\r\n偶校验:1536",
        .data=&config.uart3.parity,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT16,
        .max_value=12288,
        .min_value=0,
        .father=17,
        .next=0,
        .child=0,
        .info_str="停止位\r\n1bit:0\r\n0.5bit:4096\r\n2bit:8192\r\n1.5bit:12288",
        .data=&config.uart4.stopbits,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT8,
        .max_value=0,
        .min_value=0,
        .father=4,
        .next=0,
        .child=22,
        .info_str="串口6配置\r\nLOG",
        .data=NULL,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT32,
        .max_value=4000000,
        .min_value=4800,
        .father=21,
        .next=23,
        .child=0,
        .info_str="波特率",
        .data=&config.uart6.buad,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT16,
        .max_value=1536,
        .min_value=0,
        .father=21,
        .next=24,
        .child=0,
        .info_str="奇偶校验\r\n不校验:0\r\n奇校验:1024\r\n偶校验:1536",
        .data=&config.uart6.parity,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT16,
        .max_value=12288,
        .min_value=0,
        .father=21,
        .next=0,
        .child=0,
        .info_str="停止位\r\n1bit:0\r\n0.5bit:4096\r\n2bit:8192\r\n1.5bit:12288",
        .data=&config.uart6.stopbits,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT8,
        .max_value=0,
        .min_value=0,
        .father=1,
        .next=28,
        .child=26,
        .info_str="网络配置",
        .data=NULL,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_CHAR,
        .max_value=255,
        .min_value=0,
        .father=25,
        .next=27,
        .child=0,
        .info_str="服务器域名",
        .data=config.tcp.server_ipv4,
        .num=64
    },
    {
        .data_type=MENU_DATA_TYPE_UINT16,
        .max_value=65535,
        .min_value=0,
        .father=25,
        .next=0,
        .child=0,
        .info_str="服务器端口",
        .data=&config.tcp.server_port,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT8,
        .max_value=0,
        .min_value=0,
        .father=1,
        .next=30,
        .child=29,
        .info_str="传感器配置",
        .data=NULL,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_CHAR,
        .max_value=255,
        .min_value=0,
        .father=28,
        .next=0,
        .child=0,
        .info_str="传感器标定文件路径",
        .data=&config.ini_filename[3],
        .num=64
    },
    {
        .data_type=MENU_DATA_TYPE_UINT8,
        .max_value=1,
        .min_value=0,
        .father=1,
        .next=31,
        .child=0,
        .info_str="保存",
        .data=&operating_state.flag_write_back,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT8,
        .max_value=1,
        .min_value=0,
        .father=1,
        .next=32,
        .child=0,
        .info_str="重启",
        .data=&operating_state.flag_reboot,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_UINT8,
        .max_value=1,
        .min_value=0,
        .father=1,
        .next=33,
        .child=0,
        .info_str="恢复出厂设置\r\n警告:此选项会清空所有用户配置且不可逆,是否继续?",
        .data=&operating_state.flag_reset,
        .num=0
    },
    {
        .data_type=MENU_DATA_TYPE_RO_UINT8,
        .max_value=0,
        .min_value=0,
        .father=1,
        .next=0,
        .child=0,
        .info_str="版本",
        .data=config.version,
        .num=3
    }
};

"""